package com.example.springboot.common;

/**
 * 名称：拦截器规则
 * <p>
 * 功能：过滤请求
 * 只有携带了正确的token才能访问到需要权限的接口
 * 说明：
 * 1、请求接口前会先进入这个过滤器
 * 2、这里的方法是用来验证权限的，我们可以根据项目的需要进行修改

 * 日期：2024/1/11 9:57
 */

import cn.hutool.core.util.StrUtil;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.example.springboot.Exception.JwtInterceptorException;
import com.example.springboot.Exception.ServiceException;
import com.example.springboot.utils.AESUtil;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;

public class JwtInterceptor implements HandlerInterceptor {

    @Resource
    private UserMapper userMapper;
    @Resource
    private AdminMapper adminMapper;
    @Resource
    private StoreMapper storeMapper;


    @Value("${AESKey}")
    private String AESKey;

    @Value("${AESIV}")
    private String AESIV;

    /**
     * 过程：
     * 1、先判断请求的接口是否需要权限
     * 2、通过token获取到用户id
     * 3、通过用户id获取到用户信息
     * 4、如果用户信息不为空，则获取用户密码
     * 5、将token中的密码与用户信息的密码进行比较
     * 6、如果一致则放行，不一致则抛出异常
     * <p>
     * <p>
     * <p>
     * <p>
     * <p>
     * AES加密
     * 前端传数据只对时间戳进行加密，然后把时间戳也传过去
     * 把用户的角色也传过去，角色的信息也要加密
     * <p>
     * 前端：
     * 加密：时间戳+account + role + token
     * 请求头：role + token + 时间戳
     * <p>
     * 后端：
     * 先判断数据的是否存在和匹配
     * 不管请求头里还是加密后的数据有一项不存在，则403
     * <p>
     * 把请求头里的数据和加密后的数据进行对比，不匹配则403
     * <p>
     * <p>
     * 再匹配用户角色和请求路径是否合法
     *
     * @param request
     * @param response
     * @param handler
     * @return
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws UnsupportedEncodingException {


        response.setHeader("Content-Type", "application/json; charset=utf-8");


        // 如果不是映射到方法直接通过
        if (handler instanceof HandlerMethod) {
            AuthAccess annotation = ((HandlerMethod) handler).getMethodAnnotation(AuthAccess.class);
            if (annotation != null) {
                return true;
            }
        }


        // 获取前端数据
        String token = request.getHeader("token");
        // 防止空指针异常
        if (StrUtil.isBlank(token)) {
            token = request.getParameter("token");
        }
        String role = request.getHeader("role");
        // 防止空指针异常
        if (StrUtil.isBlank(role)) {
            role = request.getParameter("role");
        }
        String timestamp = request.getHeader("timestamp");
        // 防止空指针异常
        if (StrUtil.isBlank(timestamp)) {
            timestamp = request.getParameter("timestamp");
        }


        //AES 解密
        // data   待解密的密文
        // AESKey密钥，必须是16位字符
        // AESIV偏移量，必须是16位字符

        String data = request.getHeader("data");
        // 防止空指针异常
        if (StrUtil.isBlank(data)) {
            data = request.getParameter("data");
        }

        String decrypted = null;
        Account accountVal = null;
        Admin adminVal = null;
        Store storeVal = null;
        User userVal = null;
        String timestampAES = null;
        String roleAES = null;
        String tokenAES = null;
        try {
            // 解密
            decrypted = AESUtil.decryptAES(data, AESKey, AESIV);
//            System.out.println("解密后的数据：" + decrypted);

            //  解析JSON
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode jsonNode = objectMapper.readTree(decrypted);
            // 获取Java对象
            String accountStr = jsonNode.get("account").asText();
//            String adminStr = jsonNode.get("admin").asText();
//            String storeStr = jsonNode.get("store").asText();
//            String userStr = jsonNode.get("user").asText();
            accountVal = objectMapper.readValue(accountStr, Account.class);
//            adminVal = objectMapper.readValue(adminStr, Admin.class);
//            storeVal = objectMapper.readValue(storeStr, Store.class);
//            userVal = objectMapper.readValue(userStr, User.class);

            //
//            System.out.println(account.toString());
            // 获取其他字段
            timestampAES = jsonNode.get("timestamp").asText();
            roleAES = jsonNode.get("role").asText();
            tokenAES = jsonNode.get("token").asText();
//            System.out.println(jsonNode.get("timestamp").asText());
//            System.out.println(jsonNode.get("role").asInt());
//            System.out.println(jsonNode.get("token").asText());

        } catch (Exception e) {
            e.printStackTrace();
            throw new JwtInterceptorException("403", "验证失败!");
        }


        // 执行认证
        if (StrUtil.isBlank(token) || StrUtil.isBlank(role)) {
            throw new ServiceException("401", "请登录");
        }
        // 获取 token 中的 user id
        String id;
        try {
            id = JWT.decode(token).getAudience().get(0);
        } catch (JWTDecodeException j) {
            throw new ServiceException("401", "请登录");
        }


        // 参数未携带，则返回403
        if (StrUtil.isBlank(timestampAES) || StrUtil.isBlank(roleAES) || StrUtil.isBlank(tokenAES) || StrUtil.isBlank(timestamp)) {
            throw new JwtInterceptorException("401", "请登录!");
        }
        // 校验参数
        if (!timestampAES.equals(timestamp) || !roleAES.equals(role) || !tokenAES.equals(token)) {
            throw new JwtInterceptorException("403", "非法请求!");
        }


        // 根据token中的userid查询数据库
        if (role.equals("0")) {
            User user = userMapper.selectById(Integer.valueOf(id));
            if (user == null) {
                throw new ServiceException("401", "请登录");
            }
            // 用户密码加签验证 token
            JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
            try {
                jwtVerifier.verify(token); // 验证token
            } catch (JWTVerificationException e) {
                throw new ServiceException("401", "请登录");
            }
        } else if (role.equals("1")) {
            Store store = storeMapper.selectById(Integer.valueOf(id));
            if (store == null) {
                throw new ServiceException("401", "请登录");
            }
            // 用户密码加签验证 token
            JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(store.getPassword())).build();
            try {
                jwtVerifier.verify(token); // 验证token
            } catch (JWTVerificationException e) {
                throw new ServiceException("401", "请登录");
            }
        } else if (role.equals("2")) {
            Admin admin = adminMapper.selectById(Integer.valueOf(id));
            if (admin == null) {
                throw new ServiceException("401", "请登录");
            }
            // 用户密码加签验证 token
            JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(admin.getPassword())).build();
            try {
                jwtVerifier.verify(token); // 验证token
            } catch (JWTVerificationException e) {
                throw new ServiceException("401", "请登录");
            }
        } else {
            throw new ServiceException("401", "请登录");
        }


        // 对角色访问的请求进行处理
        String url = request.getRequestURL().toString();
        if (StrUtil.isBlank(url)) {
            throw new JwtInterceptorException("403", "请求路径异常!");
        }
        if (role.equals("0")) {
            // 用户
            if (StrUtil.containsAny(url, "/systemNotice/latest", "/blockedWord/", "/carousel/", "/comment/", "/store/", "/user/", "/orders/", "/review/", "/product/", "/ordersProduct/", "/category/", "/cartProduct/", "/cart/", "/userFavoriteProduct/")) {
                return true;
            }
            return false;

        } else if (role.equals("1")) {
            // 商家
            if (StrUtil.containsAny(url, "/withdrawal/", "/blockedWord/", "/comment/", "/store/", "/orders/", "/user/", "/orders/", "/review/", "/product/", "/ordersProduct/", "/category/")) {
                return true;
            }
            return false;
        } else if (role.equals("2")) {
            // 管理员
            return true;
        } else {
            throw new JwtInterceptorException("403", "角色异常");
        }
    }

}










